#include "wsockclienthelper.h"

#include <QJsonObject>
#include <QMetaEnum>
#include <QUuid>

/* 以下注释摘自另一个物联网项目，因此描述上和这个项目有些对不上，但意思是一样的
 * message需要有固定的格式，为json字符串：
 * command：指令，数字格式；
 * topic：订阅或发布的主题；
 * reqid：请求id，仅当command为3时有效
 * status: 状态代码，0表示成功，1表示失败，仅当command为3时有效
 * err: 错误，仅当command为3时有效
 * val：内容，字符串，格式任意，可以是普通字符串，也可以是json字符串，根据实际情况决定
 * 先定以下几种：
 * 1.订阅，command为0，例：
 *      command：0，topic："real/9001001"，表示订阅一个名为real/9001001的主题
 * 2.发布，command为1，例：
 *      command：1，topic："setadjust/9001001", val: "{\"pro_longtime\":\"0\"}"
 *      发布主题为“setadjust/9001001”的数据，内容为val中的字符串
 * 3.类似调用接口的，发布了一个主题的消息后，需要服务端马上返回结果，command为2，
 *      注：这个最好是用回调，但c++和qt才刚刚学，不会做回调；
 *      例：
 *      command：2，topic："getdeviceinfo"，reqid："47389210"，val:"9001001"
 *      服务端收到消息后，马上返回相应的结果：
 *      command：3，topic："getdeviceinfo"，reqid："47389210"，status:0，err: ""，val:"{\"sn\":"9001001",\"u\":220,\"i\":20.5}"
 *      返回的reqid和请求时发送的reqid相同，是一个随机数或者guid，这样不至于连续两次调用getdeviceinfo时，不知道服务端
 *      返回的数据是对应哪一次请求的，status为状态，0表示成功，其它表示失败，
 *      err为错误消息，当status为0时err字段为空，status为其它值时，err为错误的文本描述。
 * */
WSockClientHelper::WSockClientHelper(QObject *parent)
    : QObject{parent}
{
    m_wsocket = new QWebSocket();

    connect(m_wsocket, SIGNAL(connected()),
            this, SLOT(slotConnected()));
    connect(m_wsocket, SIGNAL(disconnected()),
            this, SLOT(slotDisconnected()));
    connect(m_wsocket, SIGNAL(textMessageReceived(QString)),
            this, SLOT(slotTextMessageReceived(QString)));
    connect(m_wsocket, SIGNAL(binaryMessageReceived(QByteArray)),
            this, SLOT(slotBinaryDataReceived(QByteArray)));
    connect(m_wsocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(slotError(QAbstractSocket::SocketError)));
}

//连接到服务器
void WSockClientHelper::connectToServer(QString url)
{
    m_wsocket->open(QUrl(url));
}

//发布消息
void WSockClientHelper::publish(QString topic, QString message)
{
    try {
        if(topic.isNull() || topic.isEmpty())
            throw tr("topic为空~");
        if(message.isNull() || message.isEmpty())
            throw tr("message为空~");

        QJsonDocument doc;
        QJsonObject qroot;
        qroot.insert("command", 1);
        qroot.insert("topic", topic);
        qroot.insert("val", message);
        doc.setObject(qroot);

        QString json = doc.toJson();
        QByteArray arr =json.toUtf8();
        this->Send(arr, true);
    } catch (...) {
        throw;
    }
}

//订阅主题
void WSockClientHelper::subscribe(QString topic)
{
    try {
        if(topic.isNull() || topic.isEmpty())
            throw tr("topic为空~");

        QJsonDocument doc;
        QJsonObject qroot;
        qroot.insert("command", 0);
        qroot.insert("topic", topic);
        doc.setObject(qroot);

        QString json = doc.toJson();
        QByteArray arr =json.toUtf8();
        this->Send(arr, true);
    } catch (...) {
        throw;
    }
}

//调用APi
void WSockClientHelper::callApi(QString topic, QString p)
{
    try {
        if(topic.isNull() || topic.isEmpty())
            throw tr("topic为空~");

        QJsonDocument doc;
        QJsonObject qroot;
        qroot.insert("command", 2);
        qroot.insert("topic", topic);
        qroot.insert("reqid", QUuid::createUuid().toString());      //由于没做回调，reqid在本项目中没什么用处
        qroot.insert("val", p);                                     //这个是参数，可以是json字符串
        doc.setObject(qroot);

        QString json = doc.toJson();
        QByteArray arr =json.toUtf8();
        this->Send(arr, true);
    } catch (...) {
        throw;
    }
}

//发送数据
void WSockClientHelper::Send(QByteArray data, bool isText)
{
    if(isText)
        data=data.insert(0,0x01);
    else
        data=data.insert(0,0x02);

    this->m_wsocket->sendBinaryMessage(data);
}

//连接成功
void WSockClientHelper::slotConnected()
{
    emit onConnectServer();
}

//连接断开
void WSockClientHelper::slotDisconnected()
{
    emit onDisconnected();
}

//收到数据
void WSockClientHelper::slotTextMessageReceived(QString message)
{
    QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
    qDebug()<<doc;

    QJsonObject jroot = doc.object();
    WSockResponse response;
    response.command = jroot["command"].toInt();
    response.err = jroot["err"].toString();
    response.reqid = jroot["reqid"].toString();
    response.status = jroot["status"].toInt();
    response.topic = jroot["topic"].toString();
    response.val = jroot["val"].toString();

    emit this->onReceiveMessage(response);
}

//收到二进制数据
void WSockClientHelper::slotBinaryDataReceived(QByteArray data)
{
    if(data[0] == 0x01)
    {
        //如果是文本
        data = data.sliced(1);
        QJsonDocument doc = QJsonDocument::fromJson(data);
        qDebug()<<doc;

        QJsonObject jroot = doc.object();
        WSockResponse response;
        response.command = jroot["command"].toInt();
        response.err = jroot["err"].toString();
        response.reqid = jroot["reqid"].toString();
        response.status = jroot["status"].toInt();
        response.topic = jroot["topic"].toString();
        response.val = jroot["val"].toString();

        emit this->onReceiveMessage(response);
    }
    else
    {
        //如果是二进制数据
        //TO_DO
    }
}

//收到错误
void WSockClientHelper::slotError(QAbstractSocket::SocketError e)
{
    emit onError();
}
